package top.codedance.iotp.client.manage.net.com232;

import com.alibaba.fastjson.JSONObject;
import top.codedance.iotp.client.manage.ManageApplication;
import com.fazecast.jSerialComm.SerialPort;
import com.sshtools.forker.client.ForkerBuilder;
import com.sshtools.forker.client.PowerShellBuilder;
import com.sshtools.forker.common.IO;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.SystemUtils;

import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;

public class CmdRunner implements Runner {
    @Override
    public byte[] exec(byte[] data) {
        try {
            String cmd = new String(data, StandardCharsets.UTF_8);
            boolean isPowershell = false;
            try {
                JSONObject tmpCmd = JSONObject.parseObject(cmd);
                cmd = tmpCmd.getString("cmd");
                isPowershell = tmpCmd.getBoolean("powershell");
            } catch (Exception e) {
            }
            return run(cmd, isPowershell);
        }catch (Exception ex){
            JSONObject endResult = new JSONObject();
            endResult.put("ok", false);
            endResult.put("context", ex.getMessage());
            return endResult.toJSONString().getBytes(StandardCharsets.UTF_8);
        }
    }

    @Override
    public byte[] exec(byte[] data, SerialPort serialPort) {
        return new byte[0];
    }

    /**
     * 运行
     * @param cmd
     * @param isPowershell
     * @return
     */
    public byte[] run(String cmd, boolean isPowershell) {
        final ByteArrayOutputStream baout = new ByteArrayOutputStream();
        JSONObject endResult = new JSONObject();
        try {
            System.out.println("Command:  " + cmd);
            ForkerBuilder builder = new ForkerBuilder().io(IO.IO);
            if (SystemUtils.IS_OS_LINUX || SystemUtils.IS_OS_MAC) {
                builder.redirectErrorStream(true).io(IO.IO).command("sh", "-c", cmd);
                final Process p = builder.start();
                ManageApplication.workerPool.submit(() -> {
                    try {
                        IOUtils.copy(p.getInputStream(), baout);
                    }catch (Exception e){}
                });
                boolean status = p.waitFor(5, TimeUnit.SECONDS);
                if(!status){
                    baout.reset();
                    baout.write("Please enter a non interactive command!".getBytes());
                }
                p.destroyForcibly();
                endResult.put("ok", true);
                endResult.put("context", new String(baout.toByteArray(), System.getProperty("sun.jnu.encoding")));
                byte[] result = endResult.toJSONString().getBytes(StandardCharsets.UTF_8);
                baout.reset();
                baout.write(result);
            } else if (SystemUtils.IS_OS_WINDOWS) {
                if(isPowershell){
                    final Process p = new PowerShellBuilder(cmd).start();
                    ManageApplication.workerPool.submit(() -> {
                        try {
                            IOUtils.copy(p.getInputStream(), baout);
                        }catch (Exception e){}
                    });
                    boolean status = p.waitFor(5, TimeUnit.SECONDS);
                    if(!status){
                        baout.reset();
                        baout.write("Please enter a non interactive command!".getBytes());
                    }
                    p.destroyForcibly();
                }else{
                    builder.command("cmd.exe", "/c", cmd);
                    builder.io(IO.SINK);
                    final Process p = builder.start();
                    ManageApplication.workerPool.submit(() -> {
                        try {
                            IOUtils.copy(p.getInputStream(), baout);
                        }catch (Exception e){}
                    });
                    boolean status = p.waitFor(5, TimeUnit.SECONDS);
                    if(!status){
                        baout.reset();
                        baout.write("Please enter a non interactive command!".getBytes());
                    }
                    p.destroyForcibly();
                }
                endResult.put("ok", true);
                endResult.put("context", new String(baout.toByteArray(), System.getProperty("sun.jnu.encoding")));
                byte[] result = endResult.toJSONString().getBytes(StandardCharsets.UTF_8);
                baout.reset();
                baout.write(result);
            } else {
                endResult.put("ok", false);
                endResult.put("context", "Unsupported this platform.");
                baout.write(endResult.toJSONString().getBytes(StandardCharsets.UTF_8));
            }
        } catch (Exception ex) {
            try {
                endResult.put("ok", false);
                endResult.put("context", "Execute command fail.");
                baout.write(endResult.toJSONString().getBytes(StandardCharsets.UTF_8));
            }catch (Exception e){}
        }
        return baout.toByteArray();
    }
}
